﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Graphics;
using Android.OS;
using Android.Support.Design.Widget;
using Android.Support.V4.App;
using Android.Support.V4.View;
using Android.Support.V4.Widget;
using Android.Support.V7.App;
using Android.Support.V7.Widget;
using Android.Views;
using Android.Widget;
using Com.Gcssloop.Widget;
using FFImageLoading;
using FFImageLoading.Views;
using mb;
using mb.Droid;
using static Android.Support.V7.Widget.GridLayoutManager;

namespace libmp
{
    public class BaseMixList<T>
    {
        protected static ILog logger = App.logger;
        protected StartActivity activity
        {
            get
            {
                return StartActivity.This;
            }
        }

        protected enum ItemType
        {
            Data,
            External,
        }
        protected class InsertItem
        {
            public View view;
            public int insertBefore;
            public int height;
            public int stickyHeight;
            public bool overwrite;
            public bool alwaysHang;
        }
        protected class SectionData
        {
            public int sectionIndex;
            public int insertViewIndex;
            public int dataStartIndex;
            public int dataCount;
            public int posStart;
            public int posCount;
        }

        protected MyRecyclerAdapter adapter;
        protected GridLayoutManager layoutManager;
        protected RecyclerView recyclerView;

        protected List<T> dataSource { set; get; }
        protected List<InsertItem> insertItems = new List<InsertItem>();
        protected List<SectionData> sections;
        protected int[] insertViewItemPositions;
        protected bool hasStickyItem;

        public View GetListView()
        {
            return recyclerView;
        }

        public void UpdateAll()
        {
            recyclerView.GetAdapter().NotifyDataSetChanged();
        }

        protected virtual View CreateCell(Dictionary<string, object> viewData)
        {
            var view = new View(activity);
            return view;
        }

        protected virtual void UpdateCell(View cell, int p, Dictionary<string, object> viewData) { }

        protected virtual ItemType GetItemType(int p)
        {
            int i = Array.FindIndex(insertViewItemPositions, n => n == p);
            if (i == -1) return ItemType.Data;

            return ItemType.External;
        }

        protected int GetDataIndex(int p)
        {
            foreach (var sec in sections)
            {
                if (sec.dataStartIndex >= 0)
                {
                    if (sec.posStart <= p && p < sec.posStart + sec.posCount)
                    {
                        return sec.dataStartIndex + (p - sec.posStart);
                    }
                }
            }
            return -1;
        }

        protected virtual void GetItemOffset(Rect rect, View view, RecyclerView.State state)
        {

            var p1 = recyclerView.GetChildAdapterPosition(view);
            // logger.Log("MyGetItemOffset", p1, p2);

            var t = GetItemType(p1);
            if (t == ItemType.Data)
            {
                int dd = 2;
                rect.Bottom = dd;
                rect.Right = dd;
                rect.Left = dd;
                rect.Top = dd;
            }
        }

        public void Setup()
        {
            SetupAdaptor();
            SetupLayoutManager();

            recyclerView = new RecyclerView(activity);
            recyclerView.LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, 0, 1);
            recyclerView.HasFixedSize = true;
            // recyclerView.SetBackgroundColor(Color.Yellow);
            recyclerView.SetLayoutManager(layoutManager);
            recyclerView.SetAdapter(adapter);
            recyclerView.AddItemDecoration(new MyItemDecoration());
            recyclerView.ScrollChange += (s, e) =>
            {
                // logger.Log("ScrollChange ");
                if (!hasStickyItem) return;
                updateSticky();
            };
        }

        protected virtual void updateSticky()
        {
            var ivSections = sections.Where(se => se.insertViewIndex >= 0);
            var itor = ivSections.GetEnumerator();
            int keepTop = 0;
            while (itor.MoveNext())
            {
                var sec = itor.Current;
                var insertItem = insertItems[sec.insertViewIndex];
                if (insertItem.stickyHeight == 0) continue;

                var vh = recyclerView.FindViewHolderForAdapterPosition(sec.posStart);
                if (vh == null)
                {
                    // logger.Log("vh not exit", sec.posStart);
                    keepTop += insertItem.stickyHeight;
                    continue;
                }

                var rect = new Rect();
                vh.ItemView.GetDrawingRect(rect);

                var rectP = new Rect(rect);
                recyclerView.OffsetDescendantRectToMyCoords(vh.ItemView, rectP);

                var frame = vh.ItemView as FrameLayout;
                var view = insertItem.view;

                var offsetY = rectP.Top;
                int remainHeight = insertItem.height - (keepTop - offsetY);
                bool gotoParent = remainHeight < insertItem.stickyHeight;
                // logger.Log("scroll", sec.posStart, offsetY, remainHeight);

                //特殊逻辑
                if (insertItem.alwaysHang) gotoParent = true;

                if (gotoParent)
                {
                    if (view.Parent == frame)
                    {
                        var parent = recyclerView.Parent as FrameLayout;
                        frame.RemoveView(view);
                        parent.AddView(view);
                        // logger.Log("switch2parent", sec.posStart);
                    }

                    int h = Math.Max(remainHeight, insertItem.stickyHeight);
                    view.LayoutParameters = new FrameLayout.LayoutParams(-1, h)
                    {
                        TopMargin = keepTop,
                    };
                    logger.Log("sticky in parent", sec.posStart, h);

                    keepTop += insertItem.stickyHeight;
                }
                else
                {
                    var lp = view.LayoutParameters as FrameLayout.LayoutParams;
                    if (view.Parent != frame)
                    {
                        var parent = recyclerView.Parent as FrameLayout;
                        parent.RemoveView(view);
                        frame.AddView(view);
                        lp.Height = -1;
                        logger.Log("switch2cell", sec.posStart);
                    }

                    if (offsetY < keepTop)
                    {
                        lp.TopMargin = keepTop - rectP.Top;
                        view.LayoutParameters = lp;
                        // view.Alpha = 1 - (-rectP.Top) * 1.0f / rectP.Height();
                    }
                    else
                    {
                        lp.TopMargin = 0;
                        view.LayoutParameters = lp;
                    }
                }
            }
        }
        protected virtual void SetupLayoutManager()
        {
            layoutManager = new GridLayoutManager(activity, 2);
            layoutManager.SetSpanSizeLookup(new MySpanSizeLookup()
            {
                MyGetSpanSize = pos =>
                {
                    var t = GetItemType(pos);
                    if (t == ItemType.Data) return 1;
                    else return 2;
                },
            });
        }

        protected virtual void SetupAdaptor()
        {
            if (adapter != null) return;
            adapter = new MyRecyclerAdapter();

            adapter.MyItemCount = () => dataSource.Count + insertItems.Count;
            adapter.MyGetItemViewType = p =>
            {
                // int i = Array.FindIndex(insertViewItemPositions, n => n == p);
                // if (i == -1) return 0;
                // else return i+1;
                return (int) GetItemType(p);
            };
            adapter.MyGetItemOffset = (rect, view, state) => this.GetItemOffset(rect, view, state);
            adapter.MyOnCreateViewHolder = (vg, type) =>
            {
                View view = null;
                Dictionary<string, object> viewData = new Dictionary<string, object>();
                if (type == (int) ItemType.Data)
                {
                    view = CreateCell(viewData);
                    view.LayoutParameters = new ViewGroup.LayoutParams(-1, -1);
                }
                else
                {
                    view = new FrameLayout(activity);
                }
                return new MyRecyclerViewHolder(view) { data = viewData };
            };

            adapter.MyOnBindViewHolder = (h, p) =>
            {
                // logger.Log("bindview", h.ItemViewType, "p1", p, "p2", h.Position, h.LayoutPosition, h.AdapterPosition);
                if (h.ItemViewType == (int) ItemType.Data)
                {
                    var viewData = (h as MyRecyclerViewHolder).data;
                    viewData["lastBindPos"] = p;
                    UpdateCell(h.ItemView, p, viewData);
                }
                else
                {
                    var fl = h.ItemView as FrameLayout;
                    int i = Array.FindIndex(insertViewItemPositions, n => n == p);
                    var insertView = insertItems[i].view;

                    //正在外挂状态
                    if (insertView.Parent != recyclerView.Parent)
                    {
                        (insertView.Parent as ViewGroup)?.RemoveView(insertView);
                        fl.RemoveAllViews();
                        fl.AddView(insertView);
                    }
                    else
                    {
                        // logger.Log("insertview is sticky, skip", p);
                    }
                    fl.LayoutParameters = new ViewGroup.LayoutParams(-1, insertItems[i].height);
                    insertView.Tag = 101;
                }
            };

        }
        public void Reload()
        {
            hasStickyItem = false;
            sections = new List<SectionData>();
            if (insertItems == null || insertItems.Count == 0)
            {
                sections.Add(new SectionData()
                {
                    sectionIndex = 0,
                        dataStartIndex = 0,
                        dataCount = dataSource.Count,
                        insertViewIndex = -1,
                        posStart = 0,
                        posCount = dataSource.Count,
                });
                insertViewItemPositions = new int[0];
            }
            else
            {
                int dsIndex = 0;
                int insertViewIndex = 0;
                int sectionIndex = 0;
                int positionNow = 0;
                insertViewItemPositions = new int[insertItems.Count];

                for (int i = 0; i < insertItems.Count; i++)
                {
                    var insertItem = insertItems[i];
                    if (insertItem.stickyHeight > 0) hasStickyItem = true;

                    int dc = insertItem.insertBefore - dsIndex;
                    //把这一节之前的数据节点做为一节
                    if (dc > 0)
                    {
                        sections.Add(new SectionData()
                        {
                            sectionIndex = sectionIndex++,
                                dataStartIndex = dsIndex,
                                dataCount = dc,
                                insertViewIndex = -1,
                                posStart = positionNow,
                                posCount = dc,
                        });
                    }
                    positionNow += dc;

                    sections.Add(new SectionData()
                    {
                        sectionIndex = sectionIndex++,
                            dataStartIndex = -1,
                            insertViewIndex = insertViewIndex++,
                            posStart = positionNow,
                            posCount = 1,
                    });
                    insertViewItemPositions[i] = positionNow;

                    dsIndex += dc;
                    positionNow += 1;
                }

                //最后一节数据
                int remain = dataSource.Count - dsIndex;
                if (remain > 0)
                {
                    sections.Add(new SectionData()
                    {
                        sectionIndex = sectionIndex++,
                            dataStartIndex = dsIndex,
                            dataCount = remain,
                            insertViewIndex = -1,
                            posStart = positionNow,
                            posCount = remain,
                    });
                }
            }

            // logger.Log("reload", string.Join(",", insertViewItemPositions));
            // logger.Log("sections", sections.Count);
            foreach (var sec in sections)
            {
                // logger.Log(sec.insertViewIndex, sec.dataStartIndex, sec.dataCount);
            }
            recyclerView.GetAdapter().NotifyDataSetChanged();
        }
    };

}